package org.framework.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.framework.annotation.MessageQueueScan;
import org.framework.callback.RabbitTemplateCallback;
import org.framework.context.MqBlankTaskDecorator;
import org.framework.context.MqSpringContextUtil;
import org.framework.converter.EnumBaseModule;
import org.framework.handle.RabbitAdminDeclaresHandle;
import org.framework.mq.MqCallbackTaskDecorator;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

/**
 * @ClassName MessageQueueAutoConfiguration
 * @Description 配置
 * @Author RayLiang
 * @Date 2022/12/12 16:18
 * @Version 1.0
 **/
@Configuration
@EnableConfigurationProperties
//@ConfigurationPropertiesScan("org")
@MessageQueueScan("${rabbitmq.scan.packages:}")
@ConfigurationProperties(prefix = "rabbitmq.converter.module")
public class MessageQueueAutoConfiguration {

    private String scan = "";
    /**
     * 实例化操作模板
     *
     * @param connectionFactory
     * @return
     */
    @Bean
    @Primary
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,MessageConverter messageConverter) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter);
        return rabbitTemplate;
    }

    @Bean
    @ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
    public RabbitAdminDeclaresHandle rabbitAdminDeclaresHandle(RabbitTemplate rabbitTemplate){
        return new RabbitAdminDeclaresHandle(rabbitTemplate);
    }


    @Bean
    public MqSpringContextUtil mqSpringContextUtil() {
        return new MqSpringContextUtil();
    }

    @Bean
    @Order(-1)
    @ConditionalOnProperty(prefix = "rabbitmq.callback", value = "enabled", matchIfMissing = true)
    public RabbitTemplateCallback rabbitTemplateCallback(RabbitTemplate rabbitTemplate, BeanFactory beanFactory) {
        //必须为true,否则无法触发returnedMessage回调，消息丢失
        rabbitTemplate.setMandatory(true);
        return new RabbitTemplateCallback(beanFactory);
    }

    @Bean("doMqCallBackTaskExecutor")
    @Order(-0)
    @ConditionalOnBean(RabbitTemplateCallback.class)
    public AsyncTaskExecutor taskExecutor(MqCallbackTaskDecorator mqCallbackTaskDecorator) {
        int corePoolSize = Runtime.getRuntime().availableProcessors();
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize((int) (corePoolSize / (1 - 0.9)));
        taskExecutor.setQueueCapacity(100);
        taskExecutor.setTaskDecorator(mqCallbackTaskDecorator);
        taskExecutor.setThreadNamePrefix("do-mq-callback-thread-pool");
        taskExecutor.initialize();
        return taskExecutor;
    }

    @Bean
    @ConditionalOnMissingBean(MqCallbackTaskDecorator.class)
    @ConditionalOnBean(RabbitTemplateCallback.class)
    public MqCallbackTaskDecorator mqCallbackTaskDecorator(){
        return new MqBlankTaskDecorator();
    }

    @Bean
    @ConditionalOnMissingBean(ObjectMapper.class)
    public ObjectMapper objectMapper(){
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);//默认为空属性不进行json解析
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        return  objectMapper;
    }

    @Bean
    public MessageConverter messageConverter(ObjectMapper objectMapper) {
        objectMapper.registerModule(new EnumBaseModule(scan.split("[;,]")));
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(objectMapper);
        return jackson2JsonMessageConverter;
    }

    public String getScan() {
        return scan;
    }

    public void setScan(String scan) {
        this.scan = scan;
    }
}
